package com.miyake.dsp.osa.lab.ui;

import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.border.BevelBorder;
import javax.swing.border.TitledBorder;

import com.miyake.dsp.osa.lab.Connector;
import com.miyake.dsp.osa.lab.LabContainer;
import com.miyake.dsp.osa.lab.file.CsvWriter;

public class OutletPanelUI extends JPanel {
	/**
	 * 
	 */
	private static final long serialVersionUID = 7275609611797566807L;
	private Map<String, JButton> connectorButtonMap = new HashMap<String, JButton>();
	private Map<String, JButton> chartButtonMap = new HashMap<String, JButton>();

	private LabContainer container;
	private static ImageIcon connectorIcon = new ImageIcon("./connector.png");
	
	
	private List<UiPanelListener> listeners = new ArrayList<UiPanelListener>();
	protected static LabContainer hoveredContainer;
	protected static String hoveredKey;
	protected static Connector copiedConnector;
	private Map<Connector, ChartFrame> charts = new HashMap<Connector, ChartFrame>();
	private static JFileChooser fileChooser;
	public void addUiPanelListener(UiPanelListener listener) {
		listeners.add(listener);
	}
	
	protected void fireStartChanging(int x, int y, Connector con, JButton button) {
		for (UiPanelListener listener : listeners) {
			listener.onStartChanging(x, y, con, button);
		}
	}
	
	protected void fireStartDragging(int x, int y, JButton conButton) {
		for (UiPanelListener listener : listeners) {
			listener.onStartDragging(x, y, conButton);
		}		
	}
	protected void fireDragging(int x, int y) {
		for (UiPanelListener listener : listeners) {
			listener.onDragging(x, y);
		}
	}
	protected void fireFinishDragging(int x, int y, LabContainer container, String key) {
		for (UiPanelListener listener : listeners) {
			listener.onFinishDragging(x, y, container, key);
		}	
	}
	protected void fireInConnectorRemove(String key) {
		for (UiPanelListener listener : listeners) {
			listener.onInConnectorRemove(key);
		}	
	}
	protected void fireOutConnectorRemove(String key) {
		for (UiPanelListener listener : listeners) {
			listener.onOutConnectorRemove(key);
		}	
	}
	public OutletPanelUI(LabContainer container) {
		initialize(container);
	}
	
	public OutletPanelUI(LabContainer container, UiPanelListener listener) {
		this.addUiPanelListener(listener);
		initialize(container);
	}
	
	private void initialize(LabContainer container) {
		this.container = container;		
		this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
		createList("Input", container.getInConnectors(), new TreeSet<String>(container.getInConnectorKeySet()), true);		
		createList("Output", container.getOutConnectors(), new TreeSet<String>(container.getOutConnectorKeySet()), false);

	}

	protected void createList(String title, final Map<String, Connector> cons, Set<String> keySet, boolean in) {
		JPanel panel = new JPanel();
		panel.setBorder(new TitledBorder(title));
		panel.setLayout(new VerticalLayout(5, VerticalLayout.LEFT));
		add(panel);
		
		boolean isSource;
		boolean isDest;
		if (in) {
			isSource = false;
			isDest = true;
		}
		else {
			isSource = true;
			isDest = false;
		}
		
		for (final String key : keySet) {
			JPanel p = new JPanel();
			p.setLayout(new FlowLayout(FlowLayout.LEFT));
			panel.add(p);

			JButton b = createConnectorButton(cons, key, isSource, isDest);
			connectorButtonMap.put(key, b);
			p.add(b);
			
			JButton name = new JButton(key);
			name.setBorder(null);
			p.add(name);
			JButton button = new JButton(/*chartIcon*/"Chart");
			chartButtonMap.put(key, button);
			button.setMargin(new Insets(0, 0, 0, 0));
			p.add(button);
			button.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent arg0) {
					showChart(key, cons.get(key));
				}
			});
			JButton csvButton = new JButton("CSV");
			csvButton.setMargin(new Insets(0, 0, 0, 0));
			p.add(csvButton);
			csvButton.addActionListener(new ActionListener() {

				@Override
				public void actionPerformed(ActionEvent arg0) {
					showFileDialog(cons.get(key));
				}
			
			});
		}
	}
	
	protected void showFileDialog(Connector connector) {
		if (fileChooser == null) {
			fileChooser = new JFileChooser();
		}
		
		fileChooser.setSelectedFile(new File(container.getCaption()+"-"+connector.getKey()+".csv"));
		int selected = fileChooser.showSaveDialog(null);
		if (selected == JFileChooser.APPROVE_OPTION){
			String filename = fileChooser.getSelectedFile().getAbsolutePath();
			new CsvWriter(connector.getData(), filename);
		}else if (selected == JFileChooser.CANCEL_OPTION){
		}else if (selected == JFileChooser.ERROR_OPTION){
		}
	}

	protected void drawWireLine() {
		this.updateUI();
	}
	
	private JButton createConnectorButton(final Map<String, Connector> cons, 
			final String key, final boolean isSource, final boolean isDestination) {
		final JButton conButton = new JButton(connectorIcon);
		conButton.setBorder(new BevelBorder(BevelBorder.LOWERED));
		conButton.addMouseListener(new MouseListener() {

			@Override
			public void mouseClicked(MouseEvent arg0) {
				if(javax.swing.SwingUtilities.isRightMouseButton(arg0)){
	//				MyPopupMenu.showWirePopup((JButton)arg0.getSource(), arg0.getLocationOnScreen());
				}
			}

			@Override
			public void mouseEntered(MouseEvent arg0) {
				if (isDestination) {
					setHoveredConnector(container, key);
				}
				
				if (isSource) {
					if (isDestination && copiedConnector != null) {
						conButton.setBorder(new BevelBorder(BevelBorder.RAISED));
					}
					else {
						
					}
				}
			}

			@Override
			public void mouseExited(MouseEvent arg0) {
				resetHoveredConnector();
				conButton.setBorder(new BevelBorder(BevelBorder.LOWERED));
			}

			@Override
			public void mousePressed(MouseEvent arg0) {
				if (isSource) {
					resetHoveredConnector();
					copiedConnector = cons.get(key);
					fireStartDragging(arg0.getXOnScreen(), arg0.getYOnScreen(), conButton);
				}
				else if (isDestination && cons.get(key).getKey() != null) {
					resetHoveredConnector();
					copiedConnector = cons.get(key);

					removeInConnector(cons, key);
					
					fireStartChanging(arg0.getXOnScreen(), arg0.getYOnScreen(), copiedConnector, conButton);
				}
				conButton.setBorder(new BevelBorder(BevelBorder.LOWERED));
			}

			@Override
			public void mouseReleased(MouseEvent arg0) {
				//System.out.println(key);
				if (canConnect()) {
					connect();
					fireFinishDragging(arg0.getXOnScreen(), arg0.getYOnScreen(), hoveredContainer, hoveredKey);
					resetHoveredConnector();
					copiedConnector = null;
				}
				else {
					copiedConnector = null;
					fireFinishDragging(arg0.getXOnScreen(), arg0.getYOnScreen(), null, null);

				}
				conButton.setBorder(new BevelBorder(BevelBorder.RAISED));
			}

		});

		conButton.addMouseMotionListener(new MouseMotionListener() {

			@Override
			public void mouseDragged(MouseEvent arg0) {
				if (isSource) {
					fireDragging(arg0.getXOnScreen(), arg0.getYOnScreen());
				}
				else if (isDestination) {
					fireDragging(arg0.getXOnScreen(), arg0.getYOnScreen());
				}
			}

			@Override
			public void mouseMoved(MouseEvent arg0) {
				// TODO Auto-generated method stub
			}
			
		});
		return conButton;
	}

	protected void resetHoveredConnector() {
		hoveredContainer = null;
		hoveredKey = null;
	}

	protected boolean canConnect() {
		if (hoveredContainer != null && hoveredKey != null && copiedConnector != null) {
			return true;
		}
		return false;
	}

	protected void showChart(String key, Connector connector) {
		ChartFrame chart = charts.get(connector);
		if (chart == null) {
			chart = new ChartFrame(connector.getParent().getCaption() + " "+connector.getKey());
			charts.put(connector, chart);
			updateData(key, connector);
		}
		chart.setVisible(true);
	}
	
	public Point getPoint(String key) {
		JButton label = connectorButtonMap.get(key);
		if (label.isShowing()) {
			return new Point(
					label.getLocationOnScreen().x + label.getWidth()/2,
					label.getLocationOnScreen().y + label.getHeight()/2);
		}
		else {
			return null;
		}
	}

	private void setHoveredConnector(LabContainer cont, String key) {
		hoveredContainer = cont;
		hoveredKey = key;
	}

	private void connect() {
		hoveredContainer.setInConnector(hoveredKey, copiedConnector);
	}

	public void updateData(String key, Connector con) {
		if (!con.isEmpty() && con.getData().getRealPart().length == 1) {
			chartButtonMap.get(key).setText(String.valueOf(con.getData().getRealPart()[0]));
		}
		ChartFrame c = charts.get(con);
		if (c != null) {
			c.setData(c.getCurveCount().toString(), con.getData().getRealPart());
		}
	}

	public Point getConnectorLocation(Connector connector) {
		Point loc = this.connectorButtonMap.get(connector.getKey()).getLocationOnScreen();
		
		return new Point(loc.x + 8, loc.y + 8);
	}

	private void removeInConnector(final Map<String, Connector> cons,
			final String key) {
		container.removeInConnector(key);
	}

	protected LabContainer getContainer() {
		return this.container;
	}

	public Component getConnectorComponent(String key) {
		return this.connectorButtonMap.get(key);
	}
}
